package com.muyan.sys.common.core.redis;

import com.muyan.sys.common.func.BusinessLogic;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Component;

import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class RedissonLockUtil {
    private static final RedissonClient redissonClient = RedissonConfig.getRedissonClient();



    /**
     * 执行加锁业务逻辑的方法，不指定锁的过期时间，无返回值
     * @param lockKey 锁的键
     * @param runnable 要执行的业务逻辑
     */
    public static void executeWithLock(String lockKey, Runnable runnable) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁，不指定过期时间
            lock.lock();
            // 执行传入的业务逻辑
            runnable.run();
        } finally {
            // 确保锁最终会被释放
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 执行加锁业务逻辑的方法，支持指定锁的过期时间，无返回值
     * @param lockKey 锁的键
     * @param leaseTime 锁的持有时间
     * @param timeUnit 时间单位
     * @param runnable 要执行的业务逻辑
     */
    public static void executeWithLock(String lockKey, long leaseTime, TimeUnit timeUnit, Runnable runnable) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁，并指定锁的过期时间
            lock.lock(leaseTime, timeUnit);
            // 执行传入的业务逻辑
            runnable.run();
        } finally {
            // 确保锁最终会被释放
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 执行加锁业务逻辑的方法，支持指定锁的过期时间和等待时间，无返回值
     * @param lockKey 锁的键
     * @param waitTime 等待获取锁的最大时间
     * @param leaseTime 锁的持有时间
     * @param timeUnit 时间单位
     * @param runnable 要执行的业务逻辑
     */
    public static void executeWithLock(String lockKey, long waitTime, long leaseTime, TimeUnit timeUnit, Runnable runnable) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁，指定等待时间和锁的过期时间
            boolean isLocked = lock.tryLock(waitTime, leaseTime, timeUnit);
            if (isLocked) {
                // 执行传入的业务逻辑
                runnable.run();
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        } finally {
            // 确保锁最终会被释放
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 执行加锁业务逻辑的方法，不指定锁的过期时间，有返回值
     * @param lockKey 锁的键
     * @param businessLogic 要执行的业务逻辑
     * @param <R> 返回结果的类型
     * @return 业务逻辑的执行结果
     */
    public static <R> R executeWithLock(String lockKey, BusinessLogic<R> businessLogic) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁，不指定过期时间
            lock.lock();
            // 执行传入的业务逻辑
            return businessLogic.execute();
        } finally {
            // 确保锁最终会被释放
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 执行加锁业务逻辑的方法，支持指定锁的过期时间，有返回值
     * @param lockKey 锁的键
     * @param leaseTime 锁的持有时间
     * @param timeUnit 时间单位
     * @param businessLogic 要执行的业务逻辑
     * @param <R> 返回结果的类型
     * @return 业务逻辑的执行结果
     */
    public static <R> R executeWithLock(String lockKey, long leaseTime, TimeUnit timeUnit, BusinessLogic<R> businessLogic) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁，并指定锁的过期时间
            lock.lock(leaseTime, timeUnit);
            // 执行传入的业务逻辑
            return businessLogic.execute();
        } finally {
            // 确保锁最终会被释放
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 执行加锁业务逻辑的方法，支持指定锁的过期时间和等待时间，有返回值
     * @param lockKey 锁的键
     * @param waitTime 等待获取锁的最大时间
     * @param leaseTime 锁的持有时间
     * @param timeUnit 时间单位
     * @param businessLogic 要执行的业务逻辑
     * @param <R> 返回结果的类型
     * @return 业务逻辑的执行结果，如果未获取到锁则返回 null
     */
    public static <R> R executeWithLock(String lockKey, long waitTime, long leaseTime, TimeUnit timeUnit, BusinessLogic<R> businessLogic) {
        RLock lock = redissonClient.getLock(lockKey);
        try {
            // 尝试获取锁，指定等待时间和锁的过期时间
            boolean isLocked = lock.tryLock(waitTime, leaseTime, timeUnit);
            if (isLocked) {
                // 执行传入的业务逻辑
                return businessLogic.execute();
            }
            return null;
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return null;
        } finally {
            // 确保锁最终会被释放
            if (lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }
}